import java.lang.reflect.*;
import java.util.HashMap;


public class SQLGenerator {
	
	private HashMap<Class<?>, String> typeMap;
	
	public SQLGenerator() {
		typeMap = new HashMap<Class<?>, String>();
		loadDefaultMappings();
	}
	
	/**
	 * Mapea cada classe com o respectivo valor correspondente em SQL
	 */
	private void loadDefaultMappings() {		
		typeMap.put(String.class, "VARCHAR(50)");
		typeMap.put(int.class, "INTEGER");
		// ...		
	}

	private String obtainType(Class<?> type) {
		return typeMap.get(type);
	}
	
	/**
	 * Gera uma instrucao de SQL para criar uma tabela para uma dada classe 
	 * @param clazz a classe
	 * @return a instrucao CREATE TABLE
	 */
	public String generateCreateTable(Class<?> clazz) {
		//recebe a classe do objecto Aluno
		
		StringBuffer sql = new StringBuffer("CREATE TABLE ");		//CREATE TABLE
		
		//obtem o nome da classe
		sql.append(clazz.getSimpleName() + " (");					//CREATE TABLE ALUNO (
		
		//obtem um array de Fields: atributos da classe
		Field[] fields = clazz.getDeclaredFields();
		
		for(int i = 0; i < fields.length; i++) {
			Field f = fields[i];
			
			//obtem a classe do atributo actual e guarda na variavel 'type'
			Class<?> type = f.getType();							//int
			
			//obtem o nome do atributo actual e guarda na variavel 'name'
			String name = f.getName();								//num
			if(i != 0)
				sql.append(", ");									//CREATE TABLE ALUNO (num INT,
			
			//dependendo da classe do atributo, devolve o respectivo valor mapeado no HashMap
			sql.append(name + " " + obtainType(type));				//CREATE TABLE ALUNO (num INT, nome VARCHAR(50)
		}
		
		sql.append(")");											//CREATE TABLE ALUNO (num INT, nome VARCHAR(50))
		
		return sql.toString();
	}
	
	/**
	 * Gera uma instrucao de SQL para inserir uma linha 
	 * (coerente com o generateCreateTable)
	 * 
	 * @param object o objecto a inserir
	 * @return a instrucao INSERT
	 */
	public String generateInsert(Object object) {
		StringBuffer sql = new StringBuffer("INSERT INTO ");	//INSERT INTO
		
		//obtem a classe do objecto
		Class<?> clazz = object.getClass();
		
		//obtem o nome da classe
		sql.append(clazz.getSimpleName());						//INSERT INTO Aluno
		sql.append(" (");										//INSERT INTO Aluno (
		
		//obtem um array de Fields: atributos da classe
		Field[] fields = clazz.getDeclaredFields();
		
		for(int i = 0; i < fields.length; i++) {
			Field f = fields[i];
			if(i != 0)
				sql.append(", ");
			
			//obtem o nome do atributo actual
			sql.append(f.getName());							//INSERT INTO Aluno (num, nome
		}
		sql.append(") VALUES (");								//INSERT INTO Aluno (num, nome) VALUES (
		for(int i = 0; i < fields.length; i++) {
			Field f = fields[i];
			
			//poe o atributo acessivel
			f.setAccessible(true);
			Object obj = null;
			try {
				//obtem o valor do atributo e guarda na variavel 'obj'
				obj = f.get(object);
			} catch (Exception e) {
				e.printStackTrace();
			} 
			
			if(i != 0)
				sql.append(", ");
			
			//converte 'Object' para 'String'
			sql.append(convertValue(obj));						//INSERT INTO Aluno (num, nome) VALUES (10, 'ze'
		}
		
		sql.append(")");										//INSERT INTO Aluno (num, nome) VALUES (10, 'ze')
		return sql.toString();
	}
	
	
	
	private String convertValue(Object obj) {
		if(obj == null)
			return "NULL";
		else {
			String text = obj.toString();
			if(obj.getClass().equals(String.class)) {
				text = "'" + text + "'";
			}
			return text;
		}
	}
}
